<template>
  <div :class="['container', type === 'table' ? 'table' : 'default']">
    <div :class="['item', type === 'table' ? 'table' : 'default']">
      <!-- 左标题 -->
      <div class="title">
        <input
          type="checkbox"
          :class="{ disabled: !leftListData.length }"
          :checked="leftCheckedAll"
          :disabled="!leftListData.length"
          @click="handleClickAll($event.target.checked, 'left')"
        />
        <select
          class="search left"
          v-model="leftListCheckedIndex"
          @change="handleChange($event.target.value)"
        >
          <option
            class="options"
            v-for="(item, index) in leftData"
            :key="item.id"
            :value="index"
            :label="item.label"
          ></option>
        </select>
        <span class="num">{{ leftListCheckedNum }}/{{ leftListTotalNum }}</span>
      </div>
      <div class="main">
        <!-- 左搜索 -->
        <div class="sousuo">
          <input
            class="input"
            type="text"
            v-model="filterLeftWord"
            :placeholder="placeholderLeft"
          />
          <i
            v-if="filterLeftWord.trim().length !== 0"
            :class="[
              'iconfont',
              'icon-qingkong',
              type === 'table' ? 'table' : 'default',
            ]"
            @click="clear('left')"
          ></i>
          <i class="iconfont icon-sousuo" @click="handleSearch('left')"></i>
        </div>
        <div class="section">
          <!-- 必须使用dragover加阻止默认行为和drop方法，不然拖拽后后会回去-->
          <!-- 列表 -->
          <ul
            ref="leftUL"
            v-if="type === 'default' && leftListData.length"
            class="data"
            @dragover.prevent
            @drop="moveItem('left', $event.target.parentElement)"
          >
            <li
              v-for="(item, index) in leftListData"
              :key="item.key"
              class="row"
              :draggable="!item.disabled"
              @dragstart="handDrag('left', item, index)"
            >
              <input
                :class="['input', item.disabled === true ? 'disabled' : '']"
                type="checkbox"
                :checked="item.$checked"
                :disabled="item.disabled"
                @click="handleClick($event.target.checked, 'left', item.key)"
                @mouseenter="handleEnter"
                @mouseleave="handleLeave"
              />
              <span
                :class="[
                  'label',
                  item.disabled === true ? 'disabled' : '',
                  item.$checked === true ? 'checked' : '',
                ]"
                @mouseenter="handleEnter"
                @mouseleave="handleLeave"
                >{{ item.label }}</span
              >
            </li>
          </ul>
          <!-- 必须使用dragover加阻止默认行为和drop方法，不然拖拽后后会回去-->
          <!-- 左表格 -->
          <table
            ref="leftTable"
            v-else-if="type === 'table' && leftListData.length"
            @dragover.prevent
            @drop="moveItem('left', $event.target.parentElement)"
          >
            <div class="scroll">
              <thead>
                <th
                  v-for="item in columnTitles"
                  :key="item"
                  @mouseenter="handleEnter"
                  @mouseleave="handleLeave"
                >
                  {{ item.text }}
                </th>
              </thead>
              <tbody>
                <tr
                  :class="[
                    'label',
                    item.disabled === true ? 'disabled' : '',
                    item.$checked === true ? 'checked' : '',
                  ]"
                  v-for="(item, index) in leftListData"
                  :key="item.key"
                  :draggable="!item.disabled"
                  @dragstart="handDrag('left', item, index)"
                >
                  <td>
                    <input
                      :class="[
                        'input',
                        item.disabled === true ? 'disabled' : '',
                      ]"
                      type="checkbox"
                      :disabled="item.disabled"
                      :checked="item.$checked"
                      @click="
                        handleClick($event.target.checked, 'left', item.key)
                      "
                      @mouseenter="handleEnter"
                      @mouseleave="handleLeave"
                    />
                  </td>
                  <td
                    v-for="(label, s) in formatItem(item)"
                    @mouseenter="handleEnter"
                    @mouseleave="handleLeave"
                  >
                    {{ item[s] }}
                  </td>
                </tr>
              </tbody>
            </div>
          </table>
          <!-- 必须使用dragover加阻止默认行为和drop方法，不然拖拽后后会回去-->
          <!-- 无数据展示 -->
          <div
            v-else
            class="noData"
            @dragover.prevent
            @drop="moveItem('left', $event.target.parentElement)"
          >
            No matching data
          </div>
        </div>
        <!-- 筛选按钮 -->
        <div class="footer">
          <button class="filterBtn" @click="setCheck('left')">
            {{ setCheckLeftText }}
          </button>
        </div>
      </div>
    </div>
    <!-- 按钮组 -->
    <div class="btns">
      <!--左按钮 -->
      <button
        ref="leftBtn"
        :class="['btn', leftBtnIsDisabled ? 'disabled' : 'default']"
        :disabled="leftBtnIsDisabled"
        @click="handClickToLeft"
      >
        <div v-if="type === 'default'">
          <i class="iconfont icon-left"></i>
          <span>{{ leftBtnText }}</span>
        </div>
        <div v-if="type === 'table'">
          <i class="iconfont icon-shang"></i><span>{{ leftBtnText }}</span>
        </div>
      </button>
      <!-- 右按钮 -->
      <button
        ref="rightBtn"
        :class="['btn', rightBtnIsDisabled ? 'disabled' : 'default']"
        :disabled="rightBtnIsDisabled"
        @click="handClickToRight"
      >
        <div v-if="type === 'default'">
          <i class="iconfont icon-right"></i><span>{{ rightBtnText }}</span>
        </div>
        <div v-if="type === 'table'">
          <i class="iconfont icon-xiangxia"></i><span>{{ rightBtnText }}</span>
        </div>
      </button>
    </div>
    <div :class="['item', type === 'table' ? 'table' : 'default']">
      <!-- 右标题 -->
      <div class="title">
        <input
          type="checkbox"
          :class="{ disabled: !rightList.length }"
          :checked="rightCheckedAll"
          :disabled="!rightList.length"
          @click="handleClickAll($event.target.checked, 'right')"
        />
        <span class="text">{{ rightTitleText }}</span>
        <span class="num"
          >{{ rightListCheckedNum }}/{{ rightListTotalNum }}</span
        >
      </div>
      <div class="main">
        <!-- 右搜索 -->
        <div class="sousuo">
          <input
            class="input"
            type="text"
            v-model="filterRightWord"
            :placeholder="placeholderRight"
          />
          <i
            v-if="filterRightWord.trim().length"
            :class="[
              'iconfont',
              'icon-qingkong',
              type === 'table' ? 'table' : 'default',
            ]"
            @click="clear('right')"
          ></i>
          <i class="iconfont icon-sousuo" @click="handleSearch('right')"></i>
        </div>
        <div class="section">
          <!-- 必须使用dragover加阻止默认行为和drop方法，不然拖拽后后会回去-->
          <!-- 列表 -->
          <ul
            ref="rightUL"
            v-if="type === 'default' && rightList.length"
            class="data"
            @dragover.prevent
            @drop="moveItem('right', $event.target.parentElement)"
          >
            <li
              v-for="(item, index) in rightList"
              :key="item.key"
              class="row"
              :draggable="!item.disabled"
              @dragstart="handDrag('right', item, index)"
            >
              <input
                :class="['input', item.disabled === true ? 'disabled' : '']"
                type="checkbox"
                :checked="item.$checked"
                :disabled="item.disabled"
                @click="handleClick($event.target.checked, 'right', item.key)"
                @mouseenter="handleEnter"
                @mouseleave="handleLeave"
              />
              <span
                :class="[
                  'label',
                  item.disabled === true ? 'disabled' : '',
                  item.$checked === true ? 'checked' : '',
                ]"
                @mouseenter="handleEnter"
                @mouseleave="handleLeave"
                >{{ item.label }}</span
              >
            </li>
          </ul>
          <!-- 必须使用dragover加阻止默认行为和drop方法，不然拖拽后后会回去-->
          <!-- 右表格 -->
          <table
            ref="rightTable"
            v-else-if="type === 'table' && rightList.length"
            @dragover.prevent
            @drop="moveItem('right', $event.target.parentElement)"
          >
            <div class="scroll">
              <thead>
                <th
                  v-for="item in columnTitles"
                  :key="item"
                  @mouseenter="handleEnter"
                  @mouseleave="handleLeave"
                >
                  {{ item.text }}
                </th>
              </thead>
              <tbody>
                <tr
                  :class="[
                    'label',
                    item.disabled === true ? 'disabled' : '',
                    item.$checked === true ? 'checked' : '',
                  ]"
                  v-for="(item, index) in rightList"
                  :key="item.key"
                  :draggable="!item.disabled"
                  @dragstart="handDrag('right', item, index)"
                >
                  <td>
                    <input
                      :class="[
                        'input',
                        item.disabled === true ? 'disabled' : '',
                      ]"
                      type="checkbox"
                      :disabled="item.disabled"
                      :checked="item.$checked"
                      @click="
                        handleClick($event.target.checked, 'right', item.key)
                      "
                      @mouseenter="handleEnter"
                      @mouseleave="handleLeave"
                    />
                  </td>
                  <td
                    v-for="(label, s) in formatItem(item)"
                    @mouseenter="handleEnter"
                    @mouseleave="handleLeave"
                  >
                    {{ item[s] }}
                  </td>
                </tr>
              </tbody>
            </div>
          </table>
          <!-- 必须使用dragover加阻止默认行为和drop方法，不然拖拽后后会回去-->
          <!-- 无数据展示 -->
          <div
            v-else
            class="noData"
            @dragover.prevent
            @drop="moveItem('right', $event.target.parentElement)"
          >
            No matching data
          </div>
        </div>
        <!-- 筛选和导出数据按钮 -->
        <div class="footer">
          <button class="filterBtn" @click="setCheck('right')">
            {{ setCheckRightText }}
          </button>
          <button class="daochuBtn" @click="emitCheckedData">
            <i class="iconfont icon-daochu1"></i> <span>导出数据</span>
          </button>
        </div>
      </div>
    </div>
  </div>
  <!-- tooltip -->
  <div v-show="toolTipIsShow" ref="toolTip" class="toolTip">
    <div class="borderLeftTop"></div>
    <div class="borderLeftBottom"></div>
    <div class="borderRightTop"></div>
    <div class="borderRightBottom"></div>
    <span>{{ toolTipText }}</span>
  </div>
</template>
<script setup>
import { ref, computed, watch, nextTick, onMounted } from "vue";
import { transter } from "./utils/props";
import {
  useComputedData,
  useLeftListCheckedIndex,
  useRightListData,
  useCheckedData,
  useButtonFun,
  useTable,
  useOriginData,
  useSearchEvent,
} from "./utils/hook";
const props = defineProps(transter);
let {
  leftBtnText,
  rightBtnText,
  rightTitleText,
  placeholderLeft,
  placeholderRight,
  type,
  leftList,
  columnTitles,
  leftSearch,
  rightSearch,
  setCheckLeftText,
  setCheckRightText,
  setCheckLeftData,
  setCheckRightData,
  isToolTip,
} = props;
const emit = defineEmits(["sendData"]);
onMounted(() => {
  if (type === "table") {
    setTableWidth(columnTitles);
  }
});
// 按钮组DOM
const leftBtn = ref();
const rightBtn = ref();
// 列表和表格DOM
const leftUL = ref();
const rightUL = ref();
const leftTable = ref();
const rightTable = ref();
// 输入筛选的关键字
let filterLeftWord = ref("");
let filterRightWord = ref("");
// toolTip相关
const toolTip = ref();
let toolTipText = ref();
let toolTipIsShow = ref(false);
// 拖拽对象相关
let startDirection = ref("left");
let startIndex = ref(0);
let dragItem = ref({});
// 将左列表数据响应式化
let leftData = ref(leftList);
// 是否搜索过
let isSouSuo = ref(false);
// 设置左边列表选中的索引
const { leftListCheckedIndex, setListCheckedIndex } = useLeftListCheckedIndex();
// 定义右边列表数据
const { rightList, getRightListData } = useRightListData();
// 定义计算属性
const {
  leftListData,
  leftListCheckedNum,
  rightListCheckedNum,
  leftListTotalNum,
  rightListTotalNum,
  leftCheckedAll,
  rightCheckedAll,
  leftBtnIsDisabled,
  rightBtnIsDisabled,
} = useComputedData(leftData.value, leftListCheckedIndex, getRightListData);
// 设置选中的数据
const { setCheckedData, setCustomizeCheckedData } = useCheckedData(
  leftListData,
  rightList,
  setCheckLeftData,
  setCheckRightData
);
// 按钮事件
const { setBtnEvent } = useButtonFun(leftListData, rightList);
// 表格设置
const { setTableWidth, setMouseEnter, setFormatItem, setSameDropEvent } =
  useTable(
    leftTable,
    rightTable,
    leftListData,
    rightList,
    leftData,
    leftListCheckedIndex,
    leftUL,
    rightUL,
    type,
    startIndex,
    dragItem
  );
// 设置元数据
const { originDataMap } = useOriginData(leftListData, rightList);
// 设置搜索方法
const { setSearch } = useSearchEvent(
  filterLeftWord,
  filterRightWord,
  leftSearch,
  rightSearch,
  leftData,
  leftListCheckedIndex,
  rightList
);
// 处理表格的行数据格式
const formatItem = (item) => {
  return setFormatItem(item);
};
// 鼠标进入方法
const handleEnter = (e) => {
  if (toolTip) {
    toolTipIsShow.value = true;
    const {
      target: { innerHTML, checked },
      clientX,
      clientY,
    } = e;
    setMouseEnter(innerHTML, checked, clientX, clientY, toolTipText, toolTip);
  }
};
// 鼠标离开方法
const handleLeave = (e) => {
  toolTipIsShow.value = false;
};
// 单选
const handleClick = (checked, leftOrRight, key) => {
  setCheckedData(leftOrRight, checked, "radio", key);
};
// 全选
const handleClickAll = (checked, leftOrRight) => {
  setCheckedData(leftOrRight, checked, "all");
};
// 设置选中的数据
const setCheck = (leftOrRight) => {
  const { leftData: updateLeftData, rightList: updateRightData } =
    setCustomizeCheckedData(leftOrRight, leftData, leftListCheckedIndex);
  if (leftOrRight === "left") {
    leftData.value = updateLeftData.value;
  } else {
    rightList.value = updateRightData.value;
  }
};
// 导出右边选中的数据
const emitCheckedData = () => {
  emit(
    "sendData",
    rightList.value.filter((e) => e.$checked)
  );
};
// 下拉方法
const handleChange = (index) => {
  isSouSuo.value = false;
  leftListCheckedIndex.value = Number(index);
  setListCheckedIndex(leftListCheckedIndex.value);
  filterLeftWord.value = "";
};
// 右按钮
const handClickToRight = () => {
  isSouSuo.value = false;
  const checkedData = setBtnEvent("left");
  rightList.value.push(...checkedData);
  leftData.value[leftListCheckedIndex.value]["data"] =
    leftListData.value.filter((e) => !e.$checked);
};
// 左按钮
const handClickToLeft = () => {
  isSouSuo.value = false;
  const checkedData = setBtnEvent("right");
  leftListData.value.push(...checkedData);
  rightList.value = rightList.value.filter((e) => !e.$checked);
};
// 拖拽开始
const handDrag = (leftOrRight, item, index) => {
  isSouSuo.value = false;
  startDirection.value = leftOrRight;
  dragItem.value = item;
  startIndex.value = index;
};
// 拖拽结束
const moveItem = (leftOrRight, e) => {
  isSouSuo.value = false;
  // 同一边交换
  if (leftOrRight === startDirection.value) {
    const { leftData: updateLeftData, rightList: updateRightData } =
      setSameDropEvent(leftOrRight, e);
    if (leftOrRight === "left") {
      leftData.value = updateLeftData.value;
    } else {
      rightList.value = updateRightData.value;
    }
    // 不同边交换
  } else {
    if (leftOrRight === "left") {
      rightList.value = rightList.value.filter((e) => e !== dragItem.value);
      leftData.value[leftListCheckedIndex.value]["data"].push(dragItem.value);
    } else {
      leftData.value[leftListCheckedIndex.value]["data"] =
        leftListData.value.filter((e) => e !== dragItem.value);
      rightList.value.push(dragItem.value);
    }
  }
};
// 搜索方法
const handleSearch = (leftOrRight) => {
  isSouSuo.value = true;
  const originData = originDataMap.get(leftOrRight);
  if (leftOrRight === "left") {
    const { leftData: updateLeftData } = setSearch(leftOrRight, originData);
    leftData.value = updateLeftData.value;
  } else {
    const { rightList: updateRightData } = setSearch(leftOrRight, originData);
    rightList.value = updateRightData.value;
  }
};
// 清空方法
const clear = (leftOrRight) => {
  leftOrRight === "left"
    ? (filterLeftWord.value = "")
    : (filterRightWord.value = "");
  handleSearch(leftOrRight);
};
// v3监听器可以接收多个来源组成的数组
// 在搜索之前设置数据备份
watch(
  [leftListData, rightList],
  ([leftnVal, rightVal]) => {
    console.log(leftnVal);
    if (!isSouSuo.value) {
      originDataMap.set("left", JSON.parse(JSON.stringify(leftnVal)));
      originDataMap.set("right", JSON.parse(JSON.stringify(rightVal)));
    }
  },
  {
    immediate: true,
    deep: true,
  }
);
// 根据表格是否渲染设置表格的宽度
watch(
  [leftListTotalNum, rightListTotalNum],
  ([leftVal, rightVal]) => {
    if (leftVal !== 0 || rightVal !== 0) {
      setTableWidth(columnTitles);
    }
  },
  { immediate: true }
);
</script>
<style scoped lang="scss">
@import url("./style/style.min.css");
</style>
